
inline Vec2::Vec2()
{
}

inline Vec2::Vec2(float x, float y)
{
	this->x=x;
	this->y=y;
}

inline Vec2::Vec2(const Vec2& right)
{
	this->x=right.x;
	this->y=right.y;
}

inline Vec2& Vec2::operator+=(const Vec2& right)
{
	x+=right.x;
	y+=right.y;
	return *this;
}

inline Vec2& Vec2::operator-=(const Vec2& right)
{
	x-=right.x;
	y-=right.y;
	return *this;
}

inline Vec2& Vec2::operator+=(float right)
{
	x+=right;
	y+=right;
	return *this;
}

inline Vec2& Vec2::operator-=(float right)
{
	x-=right;
	y-=right;
	return *this;
}

inline Vec2& Vec2::operator*=(float right)
{
	x*=right;
	y*=right;
	return *this;
}

inline Vec2& Vec2::operator/=(float right)
{
	x/=right;
	y/=right;
	return *this;
}

inline Vec2 Vec2::operator+() const
{
	return *this;
}

inline Vec2 Vec2::operator-() const
{
	return Vec2(-x, -y);
}

inline Vec2 Vec2::operator+(const Vec2& right) const
{
	return Vec2(x+right.x, y+right.y);
}

inline Vec2 Vec2::operator-(const Vec2& right) const
{
	return Vec2(x-right.x, y-right.y);
}

inline Vec2 Vec2::operator+(float right) const
{
	return Vec2(x+right, y+right);
}

inline Vec2 Vec2::operator-(float right) const
{
	return Vec2(x-right, y-right);
}

inline Vec2 Vec2::operator*(float right) const
{
	return Vec2(x*right, y*right);
}

inline Vec2 Vec2::operator/(float right) const
{
	return Vec2(x/right, y/right);
}

inline bool Vec2::operator==(const Vec2& right) const
{
	return x==right.x && y==right.y;
}

inline bool Vec2::operator!=(const Vec2& right) const
{
	return x!=right.x || y!=right.y;
}

inline Vec2 Vec2::operator&(const Vec2& right) const	// cross
{
	return Vec2(
		y*right.x - x*right.y,
		x*right.y - y*right.x);
}

inline float Vec2::operator|(const Vec2& right) const		// dot
{
	return x*right.x + y*right.y;
}

inline Vec2 operator*(float left, const Vec2& right)
{
	return Vec2(left*right.x, left*right.y);
}

inline bool Vec2::IsIdentity() const
{
	return hb_eq(x, 0.0f) && hb_eq(y, 0.0f);
}

inline float Vec2::Dot(const Vec2& right) const
{
	return x*right.x + y*right.y;
}

inline float Vec2::Length() const
{
	return sqrtf(x*x + y*y);
}

inline float Vec2::LengthSq() const
{
	return x*x + y*y;
}

inline float Vec2::Accumulate(float scale) const
{
	return (x+y)*scale;
}

inline void Vec2::Set(float x, float y)
{
	this->x=x;
	this->y=y;
}

inline void Vec2::Identify()
{
	x=0.0f;
	y=0.0f;
}

inline void Vec2::Diagonal(float v)
{
	x=v;
	y=v;
}

inline Vec2 Vec2::Abs() const
{
	return Vec2(fabsf(x), fabsf(y));
}

inline Vec2 Vec2::Negative() const
{
	return Vec2(1.0f-x, 1.0f-y);
}

inline Vec2 Vec2::Normalize() const
{
	float l=Length();
	if (l>0.0f) l=1.0f/l;
	return Vec2(x*l, y*l);
}

inline Vec2 Vec2::Interpolate(const Vec2& left, const Vec2& right, float s)
{
	float f=1.0f-s;
	return Vec2(
		right.x*f + left.x*s,
		right.y*f + left.y*s);		
}

inline Vec2 Vec2::Lerp(const Vec2& left, const Vec2& right, float s)
{
	return Vec2(
		left.x + s*(right.x-left.x),
		left.y + s*(right.y-left.y));
}

inline Vec2 Vec2::Minimize(const Vec2& left, const Vec2& right)
{
	return Vec2(
		left.x<right.x ? left.x : right.x,
		left.y<right.y ? left.y : right.y);
}

inline Vec2 Vec2::Maximize(const Vec2& left, const Vec2& right)
{
	return Vec2(
		left.x>right.x ? left.x : right.x,
		left.y>right.y ? left.y : right.y);
}

inline Vec2 Vec2::Cross(const Vec2& left, const Vec2& right)
{
	return Vec2(
		left.y*right.x - left.x*right.y,
		left.x*right.y - left.y*right.x);
}

inline float Vec2::Dot(const Vec2& left, const Vec2& right)
{
	return left.x*right.x + left.y*right.y;
}

inline /*static*/ bool Vec2::Equals(const Vec2& left, const Vec2& right, float e)
{
	return 
		hb_epsilon(left.x, right.x, e) &&
		hb_epsilon(left.y, right.y, e);
}

inline char* Vec2::ToString(char* buf, size_t size) const
{
	_snprintf_s(buf, size, size, "%f %f", x, y);
	return buf;
}

///////////////////////////////////////////////

inline Vec3::Vec3()
{
}

inline Vec3::Vec3(float x, float y, float z)
{
	this->x=x;
	this->y=y;
	this->z=z;
}

inline Vec3::Vec3(const Vec3& right)
{
	x=right.x;
	y=right.y;
	z=right.z;
}

inline Vec3::Vec3(const Vec2& right, float z/*=0.0f*/)
{
	x=right.x;
	y=right.y;
	this->z=z;
}

inline Vec3& Vec3::operator+=(const Vec3& right)
{
	x+=right.x;
	y+=right.y;
	z+=right.z;
	return *this;
}

inline Vec3& Vec3::operator-=(const Vec3& right)
{
	x-=right.x;
	y-=right.y;
	z-=right.z;
	return *this;
}

inline Vec3& Vec3::operator+=(float right)
{
	x+=right;
	y+=right;
	z+=right;
	return *this;
}

inline Vec3& Vec3::operator-=(float right)
{
	x-=right;
	y-=right;
	z-=right;
	return *this;
}

inline Vec3& Vec3::operator*=(float right)
{
	x*=right;
	y*=right;
	z*=right;
	return *this;
}

inline Vec3& Vec3::operator/=(float right)
{
	x/=right;
	y/=right;
	z/=right;
	return *this;
}

inline Vec3 Vec3::operator+() const
{
	return *this;
}

inline Vec3 Vec3::operator-() const
{
	return Vec3(-x, -y, -z);
}

inline Vec3 Vec3::operator+(const Vec3& right) const
{
	return Vec3(x+right.x, y+right.y, z+right.z);
}

inline Vec3 Vec3::operator-(const Vec3& right) const
{
	return Vec3(x-right.x, y-right.y, z-right.z);
}

inline Vec3 Vec3::operator+(float right) const
{
	return Vec3(x+right, y+right, z+right);
}

inline Vec3 Vec3::operator-(float right) const
{
	return Vec3(x-right, y-right, z-right);
}

inline Vec3 Vec3::operator*(float right) const
{
	return Vec3(x*right, y*right, z*right);
}

inline Vec3 Vec3::operator/(float right) const
{
	return Vec3(x/right, y/right, z/right);
}

inline bool Vec3::operator==(const Vec3& right) const
{
	return 
		hb_eq(x, right.x) &&
		hb_eq(y, right.y) &&
		hb_eq(z, right.z);
}

inline bool Vec3::operator!=(const Vec3& right) const
{
	return 
		!hb_eq(x, right.x) ||
		!hb_eq(y, right.y) ||
		!hb_eq(z, right.z);
}

inline Vec3 Vec3::operator&(const Vec3& right) const	// cross
{
	return Vec3(
		y*right.z - z*right.y,
		z*right.x - x*right.z,
		x*right.y - y*right.x);
}

inline float Vec3::operator|(const Vec3& right) const// dot
{
	return x*right.x + y*right.y + z*right.z;
}

inline Vec3 operator*(float left, const Vec3& right)
{
	return Vec3(left*right.x, left*right.y, left*right.z);
}

inline bool Vec3::IsIdentity() const
{
	return hb_eq(x, 0.0f) && hb_eq(y, 0.0f) && hb_eq(z, 0.0f);
}

inline float Vec3::Dot(const Vec3& right) const
{
	return x*right.x + y*right.y + z*right.z;
}

inline float Vec3::LengthSq() const
{
	return x*x + y*y + z*z;
}

inline float Vec3::Length() const
{
	return sqrtf(x*x + y*y + z*z);
}

inline void Vec3::Set(float x, float y, float z)
{
	this->x=x;
	this->y=y;
	this->z=z;
}

inline void Vec3::Set(const Vec2& v, float z)
{
	this->x=v.x;
	this->y=v.y;
	this->z=z;
}

inline void Vec3::Identify()
{
	x=0.0f;
	y=0.0f;
	z=0.0f;
}

inline void Vec3::Diagonal(float v)
{
	x=v;
	y=v;
	z=v;
}

inline void Vec3::MinTest(const Vec3& v)
{
	if (x>v.x) x=v.x;
	if (y>v.y) y=v.y;
	if (z>v.z) z=v.z;
}

inline void Vec3::MaxTest(const Vec3& v)
{
	if (x<v.x) x=v.x;
	if (y<v.y) y=v.y;
	if (z<v.z) z=v.z;
}

inline Vec3 Vec3::Abs() const
{
	return Vec3(fabsf(x), fabsf(y), fabsf(z));
}

inline Vec3 Vec3::Negative() const
{
	return Vec3(1.0f-x, 1.0f-y, 1.0f-z);
}

inline Vec3 Vec3::Normalize() const
{
	float l=Length();
	if (l>0.0f) l=1.0f/l;
	return Vec3(x*l, y*l, z*l);
}

inline Vec3 Vec3::Interpolate(const Vec3& left, const Vec3& right, float s)
{
	float f=1.0f-s;
	return Vec3(
		right.x*f + left.x*s,
		right.y*f + left.y*s,
		right.z*f + left.z*s);
}

inline Vec3 Vec3::Lerp(const Vec3& left, const Vec3& right, float s)
{
	return Vec3(
		left.x + s*(right.x-left.x),
		left.y + s*(right.y-left.y),
		left.z + s*(right.z-left.z));
}

inline Vec3 Vec3::Minimize(const Vec3& left, const Vec3& right)
{
	return Vec3(
		left.x<right.x ? left.x : right.x,
		left.y<right.y ? left.y : right.y,
		left.z<right.z ? left.z : right.z);
}

inline Vec3 Vec3::Maximize(const Vec3& left, const Vec3& right)
{
	return Vec3(
		left.x>right.x ? left.x : right.x,
		left.y>right.y ? left.y : right.y,
		left.z>right.z ? left.z : right.z);
}

inline Vec3 Vec3::TransformCoord(const Vec3& left, const Mat4& right)
{
	return Vec3(
		left.x*right._11 + left.y*right._21 + left.z*right._31 + right._41,
		left.x*right._12 + left.y*right._22 + left.z*right._32 + right._42,
		left.x*right._13 + left.y*right._23 + left.z*right._33 + right._43);
}

inline Vec3 Vec3::TransformNormal(const Vec3& left, const Mat4& right)
{
	return Vec3(
		left.x*right._11 + left.y*right._21 + left.z*right._31,
		left.x*right._12 + left.y*right._22 + left.z*right._32,
		left.x*right._13 + left.y*right._23 + left.z*right._33);
}

inline Vec3 Vec3::BuildRadiusBound(float v, const Mat4& right)
{
	return Vec3(
		fabsf(v*right._11 + v*right._21 + v*right._31),
		fabsf(v*right._12 + v*right._22 + v*right._32),
		fabsf(v*right._13 + v*right._23 + v*right._33));
}

inline Vec3 Vec3::TransformCoordAddScale(const Vec3& left, const Mat4& right, float f)
{
	return Vec3(
		(left.x*right._11 + left.y*right._21 + left.z*right._31 + right._41)*f + this->x,
		(left.x*right._12 + left.y*right._22 + left.z*right._32 + right._42)*f + this->y,
		(left.x*right._13 + left.y*right._23 + left.z*right._33 + right._43)*f + this->z);
}

inline Vec3 Vec3::TransformNormalAddScale(const Vec3& left, const Mat4& right, float f)
{
	return Vec3(
		(left.x*right._11 + left.y*right._21 + left.z*right._31)*f + this->x,
		(left.x*right._12 + left.y*right._22 + left.z*right._32)*f + this->y,
		(left.x*right._13 + left.y*right._23 + left.z*right._33)*f + this->z);
}

inline Vec3 Vec3::Cross(const Vec3& left, const Vec3& right)
{
	return Vec3(
		left.y*right.z - left.z*right.y,
		left.z*right.x - left.x*right.z,
		left.x*right.y - left.y*right.x);
}

inline float Vec3::Radius(const Vec3& min, const Vec3& max)
{
	Vec3 t=((min+max)*0.5f)-min;
	return sqrtf(t.x*t.x + t.y*t.y + t.z*t.z);
}

inline float Vec3::RadiusSq(const Vec3& min, const Vec3& max)
{
	Vec3 t=((min+max)*0.5f)-min;
	return t.x*t.x + t.y*t.y + t.z*t.z;
}

inline float Vec3::Distance(const Vec3& left, const Vec3& right)
{
	Vec3 t=left-right;
	return sqrtf(t.x*t.x + t.y*t.y + t.z*t.z);
}

inline float Vec3::DistanceSq(const Vec3& left, const Vec3& right)
{
	Vec3 t=left-right;
	return t.x*t.x + t.y*t.y + t.z*t.z;
}

inline float Vec3::Dot(const Vec3& left, const Vec3& right)
{
	return left.x*right.x + left.y*right.y + left.z*right.z;
}

inline bool Vec3::Equals(const Vec3& left, const Vec3& right, float e)
{
	return 
		hb_epsilon(left.x, right.x, e) &&
		hb_epsilon(left.y, right.y, e) &&
		hb_epsilon(left.z, right.z, e);
}

inline char* Vec3::ToString(char* buf, size_t size) const
{
	_snprintf_s(buf, size, size, "%f %f %f", x, y, z);
	return buf;
}

//////////////////////////////////////////////////////////////

inline Quat4::Quat4()
{
}

inline Quat4::Quat4(float x, float y, float z, float w/*=1.0f*/)
{
	this->x=x;
	this->y=y;
	this->z=z;
	this->w=w;
}

inline Quat4::Quat4(const Quat4& right)
{
	this->x=right.x;
	this->y=right.y;
	this->z=right.z;
	this->w=right.w;
}

inline Quat4& Quat4::operator+=(const Quat4& right)
{
	x+=right.x;
	y+=right.y;
	z+=right.z;
	w+=right.w;
	return *this;
}

inline Quat4& Quat4::operator-=(const Quat4& right)
{
	x-=right.x;
	y-=right.y;
	z-=right.z;
	w-=right.w;
	return *this;
}

inline Quat4& Quat4::operator*=(const Quat4& right)
{
	*this=*this*right;
	return *this;
}

inline Quat4& Quat4::operator+=(float right)
{
	x+=right;
	y+=right;
	z+=right;
	w+=right;
	return *this;
}

inline Quat4& Quat4::operator-=(float right)
{
	x-=right;
	y-=right;
	z-=right;
	w-=right;
	return *this;
}

inline Quat4& Quat4::operator*=(float right)
{
	x*=right;
	y*=right;
	z*=right;
	w*=right;
	return *this;
}

inline Quat4& Quat4::operator/=(float right)
{
	x/=right;
	y/=right;
	z/=right;
	w/=right;
	return *this;
}

inline Quat4 Quat4::operator+() const
{
	return *this;
}

inline Quat4 Quat4::operator-() const
{
	return Quat4(-x, -y, -z, -w);
}

inline Quat4 Quat4::operator!() const
{
	return Inverse();
}

inline Quat4 Quat4::operator+(const Quat4& right) const
{
	return Quat4(
		x+right.x,
		y+right.y,
		z+right.z,
		w+right.w);
}

inline Quat4 Quat4::operator-(const Quat4& right) const
{
	return Quat4(
		x-right.x,
		y-right.y,
		z-right.z,
		w-right.w);
}

inline Quat4 Quat4::operator*(const Quat4& right) const
{
	return Quat4(
		 x*right.w + y*right.z - z*right.y + w*right.x,
		-x*right.z + y*right.w + z*right.x + w*right.y,
		 x*right.y - y*right.x + z*right.w + w*right.z,
		-x*right.x - y*right.y - z*right.z + w*right.w);
}

inline Quat4 Quat4::operator+(float right) const
{
	return Quat4(x+right, y+right, z+right, w+right);
}

inline Quat4 Quat4::operator-(float right) const
{
	return Quat4(x-right, y-right, z-right, w-right);
}

inline Quat4 Quat4::operator*(float right) const
{
	return Quat4(x*right, y*right, z*right, w*right);
}

inline Quat4 Quat4::operator/(float right) const
{
	return Quat4(x/right, y/right, z/right, w/right);
}

inline bool Quat4::operator==(const Quat4& right) const
{
	return
		hb_eq(x, right.x) &&
		hb_eq(y, right.y) &&
		hb_eq(z, right.z) &&
		hb_eq(w, right.w); 
}

inline bool Quat4::operator!=(const Quat4& right) const
{
	return
		!hb_eq(x, right.x) ||
		!hb_eq(y, right.y) ||
		!hb_eq(z, right.z) ||
		!hb_eq(w, right.w);
}

inline Quat4 operator*(float left, const Quat4& right)
{
	return Quat4(left*right.x, left*right.y, left*right.z, left*right.w);
}

inline bool Quat4::IsIdentity() const
{
	return hb_eq(x, 0.0f) && hb_eq(y, 0.0f) && hb_eq(z, 0.0f) && hb_eq(w, 1.0f);
}

inline float Quat4::Dot(const Quat4& right) const
{
	return x*right.x + y*right.y + z*right.z + w*right.w;
}

inline float Quat4::LengthSq() const
{
	return x*x + y*y + z*z + w*w;
}

inline float Quat4::Length() const
{
	return sqrtf(x*x + y*y + z*z + w*w);
}

inline void Quat4::Set(float x, float y, float z, float w)
{
	this->x=x;
	this->y=y;
	this->z=z;
	this->w=w;
}

inline void Quat4::Set(const Vec3& v, float w/*=1.0f*/)
{
	this->x=v.x;
	this->y=v.y;
	this->z=v.z;
	this->w=w;
}

inline void Quat4::Zero()
{
	x=0.0f;
	y=0.0f;
	z=0.0f;
	w=0.0f;
}

inline void Quat4::Identify()
{
	x=0.0f;
	y=0.0f;
	z=0.0f;
	w=1.0f;
}

inline Quat4 Quat4::Abs() const
{
	return Quat4(
		fabsf(x),
		fabsf(y),
		fabsf(z),
		fabsf(w));
}

inline Quat4 Quat4::Negative() const
{
	return Quat4(
		1.0f-x,
		1.0f-y,
		1.0f-z,
		1.0f-w);
}

inline Quat4 Quat4::Conjugate() const
{
	return Quat4(-x, -y, -z, w);
}

inline Quat4 Quat4::Inverse() const
{
	float n=LengthSq();
	if (n==0.0f)
		return Quat4(0.0f, 0.0f, 0.0f, 0.0f);
	else
	{
		Quat4 t=Conjugate();
		n=1.0f/n;
		return Quat4(t.x*n, t.y*n, t.z*n, t.w*n);
	}
}

inline Quat4 Quat4::Normalize() const
{
	float l=Length();
	if (l>0.0f) l=1.0f/l;
	return Quat4(x*l, y*l, z*l, w*l);
}

inline /*static*/ Quat4 Quat4::Interpolate(const Quat4& left, const Quat4& right, float s)
{
	float f=1.0f-s;
	return Quat4(
		right.x*f + left.x*s,
		right.y*f + left.y*s,
		right.z*f + left.z*s,
		right.w*f + left.w*s);
}

inline /*static*/ Quat4 Quat4::Slerp(const Quat4& left, const Quat4& right, float t)
{
	Quat4 q1, q2;
	float f1, f2;
	float fc=Dot(left, right);

	if (fc<0.0f)
	{
		q1=-left;
		q2=right;
		fc=-fc;
	}
	else
	{
		q1=left;
		q2=right;
	}

	if ((fc+1.0f)>0.05f)
	{
		if ((1.0f-fc)<0.05f)
		{
			f1=1.0f-t;
			f2=t;
		}
		else
		{
			float fl=acosf(fc);
			float fr=sinf(fl);

			f1=sinf(fl*(1.0f-t))/fr;
			f2=sinf(fl*t)/fr;
		}
	}
	else
	{
		q2.Set(-q1.y, q1.x, -q1.w, q1.z);
		f1=sinf(3.1415926f*(0.5f-t));
		f2=sinf(3.1415926f*t);
	}

	return Quat4(
		f1*q1.x + f2*q2.x, 
		f1*q1.y + f2*q2.y, 
		f1*q1.z + f2*q2.z, 
		f1*q1.w + f2*q2.w);
}

inline /*static*/ Quat4 Quat4::Squad(const Quat4& q1, const Quat4& q2, const Quat4& q3, const Quat4& q4, float t)
{
	Quat4 t1=Slerp(q1, q4, t);
	Quat4 t2=Slerp(q2, q3, t);
	return Slerp(t1, t2, 2.0f*t*(1.0f-t));
}

inline /*static*/ Quat4 Quat4::Minimize(const Quat4& left, const Quat4& right)
{
	return Quat4(
		left.x<right.x ? left.x : right.x,
		left.y<right.y ? left.y : right.y,
		left.z<right.z ? left.z : right.z,
		left.w<right.w ? left.w : right.w);
}

inline /*static*/ Quat4 Quat4::Maximize(const Quat4& left, const Quat4& right)
{
	return Quat4(
		left.x>right.x ? left.x : right.x,
		left.y>right.y ? left.y : right.y,
		left.z>right.z ? left.z : right.z,
		left.w>right.w ? left.w : right.w);
}

inline /*static*/ Quat4 Quat4::Cross(const Quat4& q1, const Quat4& q2, const Quat4& q3)
{
	return Quat4(
		  q1.y*(q2.z*q3.w - q3.z*q2.w) - q1.z*(q2.y*q3.w - q3.y*q2.w) + q1.w*(q2.y*q3.z - q2.z*q3.y),
		-(q1.x*(q2.z*q3.w - q3.z*q2.w) - q1.z*(q2.x*q3.w - q3.x*q2.w) + q1.w*(q2.x*q3.z - q3.x*q2.z)),
		  q1.x*(q2.y*q3.w - q3.y*q2.w) - q1.y*(q2.x*q3.w - q3.x*q2.w) + q1.w*(q2.x*q3.y - q3.x*q2.y),
		-(q1.x*(q2.y*q3.z - q3.y*q2.z) - q1.y*(q2.x*q3.z - q3.x*q2.z) + q1.z*(q2.x*q3.y - q3.x*q2.y)));
}

inline /*static*/ float Quat4::Dot(const Quat4& left, const Quat4& right)
{
	return left.x*right.x + left.y*right.y + left.z*right.z + left.w*right.w;
}

inline /*static*/ bool Quat4::Equals(const Quat4& left, const Quat4& right, float e/*=0.0001f*/)
{
	return 
		hb_epsilon(left.x, right.x, e) &&
		hb_epsilon(left.y, right.y, e) &&
		hb_epsilon(left.z, right.z, e) &&
		hb_epsilon(left.w, right.w, e);
}

inline /*static*/ Quat4 Quat4::ZeroQuaternion()
{
	return Quat4(0.0f, 0.0f, 0.0f, 0.0f);
}

inline /*static*/ Quat4 Quat4::IdentifyQuaternion()
{
	return Quat4(0.0f, 0.0f, 0.0f, 1.0f);
}

inline char* Quat4::ToString(char* buf, size_t size) const
{
	_snprintf_s(buf, size, size, "%f %f %f %f", x, y, z, w);
	return buf;
}

//////////////////////////////////////////////////////////

inline Mat4::Mat4()
{
}

inline Mat4::Mat4(float _11, float _12, float _13, float _14, float _21, float _22, float _23, float _24, float _31, float _32, float _33, float _34, float _41, float _42, float _43, float _44)
{
	this->_11=_11; this->_12=_12; this->_13=_13; this->_14=_14;
	this->_21=_21; this->_22=_22; this->_23=_23; this->_24=_24;
	this->_31=_31; this->_32=_32; this->_33=_33; this->_34=_34;
	this->_41=_41; this->_42=_42; this->_43=_43; this->_44=_44;
}

inline Mat4::Mat4(const Mat4& right)
{
	this->_11=right._11; this->_12=right._12; this->_13=right._13; this->_14=right._14;
	this->_21=right._21; this->_22=right._22; this->_23=right._23; this->_24=right._24;
	this->_31=right._31; this->_32=right._32; this->_33=right._33; this->_34=right._34;
	this->_41=right._41; this->_42=right._42; this->_43=right._43; this->_44=right._44;
}

inline float& Mat4::operator()(int row, int col)
{
	return m[row][col];
}

inline float Mat4::operator()(int row, int col) const
{
	return m[row][col];
}

inline Mat4& Mat4::operator+=(const Mat4& right)
{
	_11+=right._11;
	_12+=right._12;
	_13+=right._13;
	_14+=right._14;
	_21+=right._21;
	_22+=right._22;
	_23+=right._23;
	_24+=right._24;
	_31+=right._31;
	_32+=right._32;
	_33+=right._33;
	_34+=right._34;
	_41+=right._41;
	_42+=right._42;
	_43+=right._43;
	_44+=right._44;
	return *this;
}

inline Mat4& Mat4::operator-=(const Mat4& right)
{
	_11-=right._11;
	_12-=right._12;
	_13-=right._13;
	_14-=right._14;
	_21-=right._21;
	_22-=right._22;
	_23-=right._23;
	_24-=right._24;
	_31-=right._31;
	_32-=right._32;
	_33-=right._33;
	_34-=right._34;
	_41-=right._41;
	_42-=right._42;
	_43-=right._43;
	_44-=right._44;
	return *this;
}

inline Mat4& Mat4::operator*=(const Mat4& right)
{
	*this=*this * right;
	return *this;
}

inline Mat4& Mat4::operator*=(float right)
{
	_11*=right;
	_12*=right;
	_13*=right;
	_14*=right;
	_21*=right;
	_22*=right;
	_23*=right;
	_24*=right;
	_31*=right;
	_32*=right;
	_33*=right;
	_34*=right;
	_41*=right;
	_42*=right;
	_43*=right;
	_44*=right;
	return *this;
}

inline Mat4& Mat4::operator/=(float right)
{
	_11/=right;
	_12/=right;
	_13/=right;
	_14/=right;
	_21/=right;
	_22/=right;
	_23/=right;
	_24/=right;
	_31/=right;
	_32/=right;
	_33/=right;
	_34/=right;
	_41/=right;
	_42/=right;
	_43/=right;
	_44/=right;
	return *this;
}

inline Mat4 Mat4::operator+() const
{
	return *this;
}

inline Mat4 Mat4::operator-() const
{
	return Mat4(
		-_11, -_12, -_13, -_14,
		-_21, -_22, -_23, -_24,
		-_31, -_32, -_33, -_34,
		-_41, -_42, -_43, -_44);
}

inline Mat4 Mat4::operator!() const
{
	return Inverse();
}

inline Mat4 Mat4::operator+(const Mat4& right) const
{
	return Mat4(
		_11 + right._11,
		_12 + right._12,
		_13 + right._13,
		_14 + right._14,
		_21 + right._21,
		_22 + right._22,
		_23 + right._23,
		_24 + right._24,
		_31 + right._31,
		_32 + right._32,
		_33 + right._33,
		_34 + right._34,
		_41 + right._41,
		_42 + right._42,
		_43 + right._43,
		_44 + right._44);
}

inline Mat4 Mat4::operator-(const Mat4& right) const
{
	return Mat4(
		_11 - right._11,
		_12 - right._12,
		_13 - right._13,
		_14 - right._14,
		_21 - right._21,
		_22 - right._22,
		_23 - right._23,
		_24 - right._24,
		_31 - right._31,
		_32 - right._32,
		_33 - right._33,
		_34 - right._34,
		_41 - right._41,
		_42 - right._42,
		_43 - right._43,
		_44 - right._44);
}

inline Mat4 Mat4::operator*(const Mat4& right) const
{
	Mat4 t;

	register __m128 r1, r2;
	register __m128 b1, b2, b3, b4;

	b1=_mm_loadu_ps(&right._11);
	b2=_mm_loadu_ps(&right._21);
	b3=_mm_loadu_ps(&right._31);
	b4=_mm_loadu_ps(&right._41);

	r1=_mm_mul_ps(_mm_set_ps1(this->_11),b1);
	r2=_mm_mul_ps(_mm_set_ps1(this->_21),b1);
	r1=_mm_add_ps(r1, _mm_mul_ps(_mm_set_ps1(this->_12),b2));
	r2=_mm_add_ps(r2, _mm_mul_ps(_mm_set_ps1(this->_22),b2));
	r1=_mm_add_ps(r1, _mm_mul_ps(_mm_set_ps1(this->_13),b3));
	r2=_mm_add_ps(r2, _mm_mul_ps(_mm_set_ps1(this->_23),b3));
	r1=_mm_add_ps(r1, _mm_mul_ps(_mm_set_ps1(this->_14),b4));
	r2=_mm_add_ps(r2, _mm_mul_ps(_mm_set_ps1(this->_24),b4));
	_mm_storeu_ps(&t._11, r1);
	_mm_storeu_ps(&t._21, r2);

	r1=_mm_mul_ps(_mm_set_ps1(this->_31),b1);
	r2=_mm_mul_ps(_mm_set_ps1(this->_41),b1);
	r1=_mm_add_ps(r1, _mm_mul_ps(_mm_set_ps1(this->_32),b2));
	r2=_mm_add_ps(r2, _mm_mul_ps(_mm_set_ps1(this->_42),b2));
	r1=_mm_add_ps(r1, _mm_mul_ps(_mm_set_ps1(this->_33),b3));
	r2=_mm_add_ps(r2, _mm_mul_ps(_mm_set_ps1(this->_43),b3));
	r1=_mm_add_ps(r1, _mm_mul_ps(_mm_set_ps1(this->_34),b4));
	r2=_mm_add_ps(r2, _mm_mul_ps(_mm_set_ps1(this->_44),b4));
	_mm_storeu_ps(&t._31, r1);
	_mm_storeu_ps(&t._41, r2);

	return t;
}

inline Mat4 Mat4::operator*(float right) const
{
	return Mat4(
		_11 * right,
		_12 * right,
		_13 * right,
		_14 * right,
		_21 * right,
		_22 * right,
		_23 * right,
		_24 * right,
		_31 * right,
		_32 * right,
		_33 * right,
		_34 * right,
		_41 * right,
		_42 * right,
		_43 * right,
		_44 * right);
}

inline Mat4 Mat4::operator/(float right) const
{
	return Mat4(
		_11 / right,
		_12 / right,
		_13 / right,
		_14 / right,
		_21 / right,
		_22 / right,
		_23 / right,
		_24 / right,
		_31 / right,
		_32 / right,
		_33 / right,
		_34 / right,
		_41 / right,
		_42 / right,
		_43 / right,
		_44 / right);
}

inline bool Mat4::operator==(const Mat4& right) const
{
	return memcmp(this, &right, sizeof(Mat4))==0;
}

inline bool Mat4::operator!=(const Mat4& right) const
{
	return memcmp(this, &right, sizeof(Mat4))!=0;
}

inline Mat4 operator*(float left, const Mat4& right)
{
	return Mat4(
		left * right._11,
		left * right._12,
		left * right._13,
		left * right._14,
		left * right._21,
		left * right._22,
		left * right._23,
		left * right._24,
		left * right._31,
		left * right._32,
		left * right._33,
		left * right._34,
		left * right._41,
		left * right._42,
		left * right._43,
		left * right._44);
}

inline bool Mat4::IsIdentity() const
{
	return 
		_11 == 1.0f && _12 == 0.0f && _13 == 0.0f && _14 == 0.0f &&
		_21 == 0.0f && _22 == 1.0f && _23 == 0.0f && _24 == 0.0f &&
		_31 == 0.0f && _32 == 0.0f && _33 == 1.0f && _34 == 0.0f &&
		_41 == 0.0f && _42 == 0.0f && _43 == 0.0f && _44 == 1.0f;
}

inline void Mat4::Zero()
{
	_11=_12=_13=_14=
	_21=_22=_23=_24=
	_31=_32=_33=_34=
	_41=_42=_43=_44=0.0f;
}

inline void Mat4::Identify()
{
	_12=_13=_14=
	_21=_23=_24=
	_31=_32=_34=
	_41=_42=_43=0.0f;
	_11=_22=_33=_44=1.0f;
}

inline void Mat4::Diagonal(float v)
{
	_12=_13=_14=
	_21=_23=_24=
	_31=_32=_34=
	_41=_42=_43=0.0f;
	_11=_22=_33=_44=v;
}

inline Mat4 Mat4::Inverse() const
{
	Mat4 t;

	static const __declspec(align(16)) int _PNNP[4]={0x00000000, 0x80000000, 0x80000000, 0x00000000};
	__m128 A,B,C,D;
	__m128 iA,iB,iC,iD;
	__m128 DC,AB;
	__m128 dA,dB,dC,dD;
	__m128 det,d,d1,d2;
	__m128 rd;
	__m128 b1, b2, b3, b4;

	b1=_mm_loadu_ps(&this->_11);
	b2=_mm_loadu_ps(&this->_21);
	b3=_mm_loadu_ps(&this->_31);
	b4=_mm_loadu_ps(&this->_41);

	A=_mm_movelh_ps(b1, b2);
	B=_mm_movehl_ps(b2, b1);
	C=_mm_movelh_ps(b3, b4);
	D=_mm_movehl_ps(b4, b3);

	AB=_mm_mul_ps(_mm_shuffle_ps(A,A,0x0F),B);
	AB=_mm_sub_ps(AB,_mm_mul_ps(_mm_shuffle_ps(A,A,0xA5),_mm_shuffle_ps(B,B,0x4E)));
	DC=_mm_mul_ps(_mm_shuffle_ps(D,D,0x0F),C);
	DC=_mm_sub_ps(DC,_mm_mul_ps(_mm_shuffle_ps(D,D,0xA5),_mm_shuffle_ps(C,C,0x4E)));

	dA=_mm_mul_ps(_mm_shuffle_ps(A,A,0x5F),A);
	dA=_mm_sub_ss(dA,_mm_movehl_ps(dA,dA));
	dB=_mm_mul_ps(_mm_shuffle_ps(B,B,0x5F),B);
	dB=_mm_sub_ss(dB,_mm_movehl_ps(dB,dB));

	dC=_mm_mul_ps(_mm_shuffle_ps(C,C,0x5F),C);
	dC=_mm_sub_ss(dC,_mm_movehl_ps(dC,dC));
	dD=_mm_mul_ps(_mm_shuffle_ps(D,D,0x5F),D);
	dD=_mm_sub_ss(dD,_mm_movehl_ps(dD,dD));

	d=_mm_mul_ps(_mm_shuffle_ps(DC,DC,0xD8),AB);

	iD=_mm_mul_ps(_mm_shuffle_ps(C,C,0xA0),_mm_movelh_ps(AB,AB));
	iD=_mm_add_ps(iD,_mm_mul_ps(_mm_shuffle_ps(C,C,0xF5),_mm_movehl_ps(AB,AB)));
	iA=_mm_mul_ps(_mm_shuffle_ps(B,B,0xA0),_mm_movelh_ps(DC,DC));
	iA=_mm_add_ps(iA,_mm_mul_ps(_mm_shuffle_ps(B,B,0xF5),_mm_movehl_ps(DC,DC)));

	d=_mm_add_ps(d,_mm_movehl_ps(d,d));
	d=_mm_add_ss(d,_mm_shuffle_ps(d,d,1));
	d1=_mm_mul_ps(dA,dD);
	d2=_mm_mul_ps(dB,dC);

	iD=_mm_sub_ps(_mm_mul_ps(D,_mm_shuffle_ps(dA,dA,0)),iD);
	iA=_mm_sub_ps(_mm_mul_ps(A,_mm_shuffle_ps(dD,dD,0)),iA);

	det=_mm_sub_ss(_mm_add_ss(d1,d2),d);
	rd=_mm_div_ss(_mm_set_ss(1.0f),det);
	// ZERO_SINGULAR
	//rd=_mm_and_ps(_mm_cmpneq_ss(det,_mm_setzero_ps()),rd);

	iB=_mm_mul_ps(D,_mm_shuffle_ps(AB,AB,0x33));
	iB=_mm_sub_ps(iB,_mm_mul_ps(_mm_shuffle_ps(D,D,0xB1),_mm_shuffle_ps(AB,AB,0x66)));
	iC=_mm_mul_ps(A,_mm_shuffle_ps(DC,DC,0x33));
	iC=_mm_sub_ps(iC,_mm_mul_ps(_mm_shuffle_ps(A,A,0xB1),_mm_shuffle_ps(DC,DC,0x66)));

	rd=_mm_shuffle_ps(rd,rd,0);
	rd=_mm_xor_ps(rd,(*(__m128*)&_PNNP));

	iB=_mm_sub_ps(_mm_mul_ps(C,_mm_shuffle_ps(dB,dB,0)),iB);
	iC=_mm_sub_ps(_mm_mul_ps(B,_mm_shuffle_ps(dC,dC,0)),iC);

	iA=_mm_div_ps(iA,rd);
	iB=_mm_div_ps(iB,rd);
	iC=_mm_div_ps(iC,rd);
	iD=_mm_div_ps(iD,rd);

	_mm_storeu_ps(&t._11,_mm_shuffle_ps(iA,iB,0x77));
	_mm_storeu_ps(&t._21,_mm_shuffle_ps(iA,iB,0x22));
	_mm_storeu_ps(&t._31,_mm_shuffle_ps(iC,iD,0x77));
	_mm_storeu_ps(&t._41,_mm_shuffle_ps(iC,iD,0x22));

	return t;
}

inline Mat4 Mat4::Transpose() const
{
	Mat4 t;
	
	__m128 mm[4];

	mm[0]=_mm_unpacklo_ps(_mm_loadu_ps(&this->_11), _mm_loadu_ps(&this->_21));
	mm[1]=_mm_unpacklo_ps(_mm_loadu_ps(&this->_31), _mm_loadu_ps(&this->_41));
	mm[2]=_mm_unpackhi_ps(_mm_loadu_ps(&this->_11), _mm_loadu_ps(&this->_21));
	mm[3]=_mm_unpackhi_ps(_mm_loadu_ps(&this->_31), _mm_loadu_ps(&this->_41));

	_mm_storeu_ps(&t._11, _mm_movelh_ps(mm[0], mm[1]));
	_mm_storeu_ps(&t._21, _mm_movehl_ps(mm[1], mm[0]));
	_mm_storeu_ps(&t._31, _mm_movelh_ps(mm[2], mm[3]));
	_mm_storeu_ps(&t._41, _mm_movehl_ps(mm[3], mm[2]));

	return t;
}

inline /*static*/ Mat4 Mat4::Location(const Vec3& v)
{
	return Mat4(
		1.0f, 0.0f, 0.0f, 0.0f,
		0.0f, 1.0f, 0.0f, 0.0f,
		0.0f, 0.0f, 1.0f, 0.0f,
		v.x,  v.y,  v.z,  1.0f);
}

inline /*static*/ Mat4 Mat4::Scaling(const Vec3& v)
{
	return Mat4(
		v.x, 0.0f, 0.0f, 0.0f,
		0.0f, v.y, 0.0f, 0.0f,
		0.0f, 0.0f, v.z, 0.0f,
		0.0f, 0.0f, 0.0f, 1.0f);
}

inline /*static*/ Mat4 Mat4::Rotation(const Vec3& v)
{
	float sr, sp, sy;
	float cr, cp, cy;
	float srsp, crsp;

	sr=sinf(v.x); cr=cosf(v.x);
	sp=sinf(v.y); cp=cosf(v.x);
	sy=sinf(v.z); cy=cosf(v.x);
	srsp=sr*sp;
	crsp=cr*sp;

	return Mat4(
		cp*cy,
		cp*sy,
		-sp,
		0.0f,

		srsp*cy - cr*sy,
		srsp*sy + cr*cy,
		sr*cp,
		0.0f,

		crsp*cy + sr*sy,
		crsp*sy - sr*cy,
		cr*cp,
		0.0f,

		0.0f,
		0.0f,
		0.0f,
		1.0f);
}

inline /*static*/ Mat4 Mat4::Rotation(const Quat4& q)
{
	return Mat4(
		1.0f - 2.0f*q.y*q.y - 2.0f*q.z*q.z, 
		2.0f*q.x*q.y + 2.0f*q.z*q.w, 
		2.0f*q.x*q.z - 2.0f*q.y*q.w, 
		0.0f,

		2.0f*q.x*q.y - 2.0f*q.z*q.w, 
		1.0f - 2.0f*q.x*q.x - 2.0f*q.z*q.z, 
		2.0f*q.z*q.y + 2.0f*q.x*q.w, 
		0.0f,

		2.0f*q.x*q.z + 2.0f*q.y*q.w, 
		2.0f*q.z*q.y - 2.0f*q.x*q.w, 
		1.0f - 2.0f*q.x*q.x - 2.0f*q.y*q.y, 
		0.0f,

		0.0f, 
		0.0f, 
		0.0f, 
		1.0f);
}

inline /*static*/ Mat4 Mat4::Transform(const Vec3& loc, const Quat4& rot, const Vec3& scl)
{
	Mat4 m=Rotation(rot);
	float* f=m._m;
	f[0] +=loc.x*f[3];
	f[1] +=loc.y*f[3];
	f[2] +=loc.z*f[3];
	f[4] +=loc.x*f[7];
	f[5] +=loc.y*f[7];
	f[6] +=loc.z*f[7];
	f[8] +=loc.x*f[11];
	f[9] +=loc.y*f[11];
	f[10]+=loc.z*f[11];
	f[12]+=loc.x*f[15];
	f[13]+=loc.y*f[15];
	f[14]+=loc.z*f[15];
	f[0] *=scl.x;
	f[1] *=scl.x;
	f[2] *=scl.x;
	f[3] *=scl.x;
	f[4] *=scl.y;
	f[5] *=scl.y;
	f[6] *=scl.y;
	f[7] *=scl.y;
	f[8] *=scl.z;
	f[9] *=scl.z;
	f[10]*=scl.z;
	f[11]*=scl.z;
	return m;
}

inline /*static*/ Mat4 Mat4::Transform(const Vec3& loc, const Vec3& rot, const Vec3& scl)
{
	Mat4 m=Rotation(rot);
	float* f=m._m;
	f[0] +=loc.x*f[3];
	f[1] +=loc.y*f[3];
	f[2] +=loc.z*f[3];
	f[4] +=loc.x*f[7];
	f[5] +=loc.y*f[7];
	f[6] +=loc.z*f[7];
	f[8] +=loc.x*f[11];
	f[9] +=loc.y*f[11];
	f[10]+=loc.z*f[11];
	f[12]+=loc.x*f[15];
	f[13]+=loc.y*f[15];
	f[14]+=loc.z*f[15];
	f[0] *=scl.x;
	f[1] *=scl.x;
	f[2] *=scl.x;
	f[3] *=scl.x;
	f[4] *=scl.y;
	f[5] *=scl.y;
	f[6] *=scl.y;
	f[7] *=scl.y;
	f[8] *=scl.z;
	f[9] *=scl.z;
	f[10]*=scl.z;
	f[11]*=scl.z;
	return m;
}

inline /*static*/ bool Mat4::Equals(const Mat4& left, const Mat4& right)
{
	return memcmp(&left, &right, sizeof(Mat4))==0;
}

inline /*static*/ Mat4 Mat4::ZeroMatrix()
{
	return Mat4(
		0.0f, 0.0f, 0.0f, 0.0f,
		0.0f, 0.0f, 0.0f, 0.0f,
		0.0f, 0.0f, 0.0f, 0.0f,
		0.0f, 0.0f, 0.0f, 0.0f);
}

inline /*static*/ Mat4 Mat4::IdentifyMatrix()
{
	return Mat4(
		1.0f, 0.0f, 0.0f, 0.0f,
		0.0f, 1.0f, 0.0f, 0.0f,
		0.0f, 0.0f, 1.0f, 0.0f,
		0.0f, 0.0f, 0.0f, 1.0f);
}

inline char* Mat4::ToString(char* buf, size_t size) const
{
	_snprintf_s(buf, size, size, "%f %f %f %f %f %f %f %f %f %f %f %f %f %f %f %f",
		_11, _12, _13, _14,
		_21, _22, _23, _24,
		_31, _32, _33, _34,
		_41, _42, _43, _44);
	return buf;
}

//////////////////////////////////////////////////////////////////////////

inline ColorValue::ColorValue()
{
}

inline ColorValue::ColorValue(float r, float g, float b, float a)
{
	this->r=r;
	this->g=g;
	this->b=b;
	this->a=a;
}

inline ColorValue::ColorValue(unsigned int value)
{
	float f=1.0f/255.0f;
	this->b=(float)(value&255)*f; value>>=8;
	this->g=(float)(value&255)*f; value>>=8;
	this->r=(float)(value&255)*f; value>>=8;
	this->a=(float)(value&255)*f; value>>=8;
}

inline ColorValue::ColorValue(const ColorValue& right)
{
	this->r=right.r;
	this->g=right.g;
	this->b=right.b;
	this->a=right.a;
}

inline ColorValue::operator unsigned int() const
{
	unsigned int R=(this->r>=1.0f) ? 0xff : (this->r<=0.0f) ? 0x00 : (unsigned int)(this->r*255.0f+0.5f);
	unsigned int G=(this->g>=1.0f) ? 0xff : (this->g<=0.0f) ? 0x00 : (unsigned int)(this->g*255.0f+0.5f);
	unsigned int B=(this->b>=1.0f) ? 0xff : (this->b<=0.0f) ? 0x00 : (unsigned int)(this->b*255.0f+0.5f);
	unsigned int A=(this->a>=1.0f) ? 0xff : (this->a<=0.0f) ? 0x00 : (unsigned int)(this->a*255.0f+0.5f);
	return (A<<24)|(R<<16)|(G<<8)|B;
}

inline ColorValue& ColorValue::operator+=(const ColorValue& right)
{
	r+=right.r;
	g+=right.g;
	b+=right.b;
	a+=right.a;
	return *this;
}

inline ColorValue& ColorValue::operator-=(const ColorValue& right)
{
	r-=right.r;
	g-=right.g;
	b-=right.b;
	a-=right.a;
	return *this;
}

inline ColorValue& ColorValue::operator*=(float right)
{
	r*=right;
	g*=right;
	b*=right;
	a*=right;
	return *this;
}

inline ColorValue& ColorValue::operator/=(float right)
{
	r/=right;
	g/=right;
	b/=right;
	a/=right;
	return *this;
}

inline ColorValue ColorValue::operator+() const
{
	return *this;
}

inline ColorValue ColorValue::operator-() const
{
	return ColorValue(-r, -g, -b, -a);
}

inline ColorValue ColorValue::operator+(const ColorValue& right) const
{
	return ColorValue(r+right.r, g+right.g, b+right.b, a+right.a);
}

inline ColorValue ColorValue::operator-(const ColorValue& right) const
{
	return ColorValue(r-right.r, g-right.g, b-right.b, a-right.a);
}

inline ColorValue ColorValue::operator*(float right) const
{
	return ColorValue(r*right, g*right, b*right, a*right);
}

inline ColorValue ColorValue::operator/(float right) const
{
	return ColorValue(r/right, g/right, b/right, a/right);
}

inline bool ColorValue::operator==(const ColorValue& right) const
{
	return 
		hb_eq(r, right.r) &&
		hb_eq(g, right.g) &&
		hb_eq(b, right.b) &&
		hb_eq(a, right.a);
}

inline bool ColorValue::operator!=(const ColorValue& right) const
{
	return 
		!hb_eq(r, right.r) ||
		!hb_eq(g, right.g) ||
		!hb_eq(b, right.b) ||
		!hb_eq(a, right.a);
}

inline unsigned int ColorValue::ToUint() const
{
	unsigned int R=(r>=1.0f) ? 0xff : (r<=0.0f) ? 0x00 : (unsigned int)(r*255.0f+0.5f);
	unsigned int G=(g>=1.0f) ? 0xff : (g<=0.0f) ? 0x00 : (unsigned int)(g*255.0f+0.5f);
	unsigned int B=(b>=1.0f) ? 0xff : (b<=0.0f) ? 0x00 : (unsigned int)(b*255.0f+0.5f);
	unsigned int A=(a>=1.0f) ? 0xff : (a<=0.0f) ? 0x00 : (unsigned int)(a*255.0f+0.5f);
	return (A<<24)|(R<<16)|(G<<8)|B;
}

inline unsigned int ColorValue::ToUintSimple() const
{
	unsigned char R=(unsigned char)(r*255.0f+0.5f);
	unsigned char G=(unsigned char)(g*255.0f+0.5f);
	unsigned char B=(unsigned char)(b*255.0f+0.5f);
	unsigned char A=(unsigned char)(a*255.0f+0.5f);
	return ((unsigned int)A<<24)|((unsigned int)R<<16)|((unsigned int)G<<8)|(unsigned int)B;
}

inline void ColorValue::Set(float r, float g, float b, float a/*=1.0f*/)
{
	this->r=r;
	this->g=g;
	this->b=b;
	this->a=a;
}

inline void ColorValue::Set(unsigned int n)
{
	float f=1.0f/255.0f;
	this->b=(float)(n&255)*f; n>>=8;
	this->g=(float)(n&255)*f; n>>=8;
	this->r=(float)(n&255)*f; n>>=8;
	this->a=(float)(n&255)*f; n>>=8;
}

inline ColorValue ColorValue::Negative() const
{
	return ColorValue(1.0f-r, 1.0f-g, 1.0f-b, a);
}

inline ColorValue ColorValue::Contrast(float s) const
{
	return ColorValue(
		0.5f+s*(r-0.5f),
		0.5f+s*(g-0.5f),
		0.5f+s*(b-0.5f),
		a);
}

inline ColorValue ColorValue::Saturation(float s) const
{
	float f=r*0.2125f + g*0.7154f + b*0.0721f;
	return ColorValue(
		f+s*(r-f),
		f+s*(g-f),
		f+s*(b-f),
		a);
}

inline ColorValue ColorValue::Brighten(float s) const
{
	ColorValue c(r*s, g*s, b*s, a);
	if (c.r>1.0f) c.r=1.0f;
	if (c.g>1.0f) c.g=1.0f;
	if (c.b>1.0f) c.b=1.0f;
	return c;
}

inline /*static*/ ColorValue ColorValue::Interpolate(const ColorValue& left, const ColorValue& right, float s)
{
	float f=1.0f-s;
	return ColorValue(
		right.r*f + left.r*s,
		right.g*f + left.g*s,
		right.b*f + left.b*s,
		right.a*f + left.a*s);
}

inline /*static*/ ColorValue ColorValue::Lerp(const ColorValue& left, const ColorValue& right, float s)
{
	return ColorValue(
		left.r + s*(right.r-left.r),
		left.g + s*(right.g-left.g),
		left.b + s*(right.b-left.b),
		left.a + s*(right.a-left.a));
}

inline /*static*/ ColorValue ColorValue::Modulate(const ColorValue& left, const ColorValue& right)
{
	return ColorValue(
		left.r*right.r,
		left.g*right.g,
		left.b*right.b,
		left.a*right.a);
}

inline /*static*/ ColorValue ColorValue::Minimize(const ColorValue& left, const ColorValue& right)
{
	return ColorValue(
		left.r<right.r ? left.r : right.r,
		left.g<right.g ? left.g : right.g,
		left.b<right.b ? left.b : right.b,
		left.a<right.a ? left.a : right.a);
}

inline /*static*/ ColorValue ColorValue::Maximize(const ColorValue& left, const ColorValue& right)
{
	return ColorValue(
		left.r>right.r ? left.r : right.r,
		left.g>right.g ? left.g : right.g,
		left.b>right.b ? left.b : right.b,
		left.a>right.a ? left.a : right.a);
}

inline /*static*/ bool ColorValue::Equals(const ColorValue& left, const ColorValue& right, float e/*=HBM_EPSILON*/)
{
	return 
		hb_epsilon(left.r, right.r, e) &&
		hb_epsilon(left.g, right.g, e) &&
		hb_epsilon(left.b, right.b, e) &&
		hb_epsilon(left.a, right.a, e);
}

inline /*static*/ ColorValue ColorValue::Black(float a/*=1.0f*/)
{
	return ColorValue(0.0f, 0.0f, 0.0f, a);
}

inline /*static*/ ColorValue ColorValue::White(float a/*=1.0f*/)
{
	return ColorValue(1.0f, 1.0f, 1.0f, a);
}

inline char* ColorValue::ToString(char* buf, size_t size) const
{
	_snprintf_s(buf, size, size, "%f %f %f %f", r, g, b, a);
	return buf;
}

//////////////////////////////////////////////////////////////////////////

inline Vec2h::Vec2h()
{

}

inline Vec2h::Vec2h(const Vec2h& right)
{
	this->x=right.x;
	this->y=right.y;
}

inline Vec2h::Vec2h(float x, float y)
{
	this->x=tpl::FloatToHalf(x);
	this->y=tpl::FloatToHalf(y);
}

inline Vec2 Vec2h::ToVec2() const
{
	return Vec2(
		tpl::HalfToFloat(x),
		tpl::HalfToFloat(y));
}

inline void Vec2h::Set(float x, float y)
{
	this->x=tpl::FloatToHalf(x);
	this->y=tpl::FloatToHalf(y);
}

inline char* Vec2h::ToString(char* buf, size_t size) const
{
	Vec2 v(ToVec2());
	_snprintf_s(buf, size, size, "%f %f", v.x, v.y);
	return buf;
}

//////////////////////////////////////////////////////////////////////////

inline Vec3h::Vec3h()
{

}

inline Vec3h::Vec3h(const Vec3h& right)
{
	this->x=right.x;
	this->y=right.y;
	this->z=right.z;
}

inline Vec3h::Vec3h(float x, float y, float z)
{
	this->x=tpl::FloatToHalf(x);
	this->y=tpl::FloatToHalf(y);
	this->z=tpl::FloatToHalf(z);
}

inline Vec3 Vec3h::ToVec3() const
{
	return Vec3(
		tpl::HalfToFloat(x),
		tpl::HalfToFloat(y),
		tpl::HalfToFloat(z));
}

inline void Vec3h::Set(float x, float y, float z)
{
	this->x=tpl::FloatToHalf(x);
	this->y=tpl::FloatToHalf(y);
	this->z=tpl::FloatToHalf(z);
}

inline void Vec3h::Set(const Vec3& v)
{
	this->x=tpl::FloatToHalf(v.x);
	this->y=tpl::FloatToHalf(v.x);
	this->z=tpl::FloatToHalf(v.z);
}

inline char* Vec3h::ToString(char* buf, size_t size) const
{
	Vec3 v(ToVec3());
	_snprintf_s(buf, size, size, "%f %f %f", v.x, v.y, v.z);
	return buf;
}

inline bool Vec3h::Equals(const Vec3h& left, const Vec3h& right)
{
	return
		left.x==right.x &&
		left.y==right.y &&
		left.z==right.z;
}

inline BoundBox::BoundBox()
{
	this->min.Set(FLT_MAX, FLT_MAX, FLT_MAX);
	this->max.Set(-999999.0f, -999999.0f, -999999.0f);
	this->ctr.Set(0.0f, 0.0f, 0.0f);
	this->rad=0.0f;
}

inline void BoundBox::Reset()
{
	this->min.Set(FLT_MAX, FLT_MAX, FLT_MAX);
	this->max.Set(-999999.0f, -999999.0f, -999999.0f);
	this->ctr.Set(0.0f, 0.0f, 0.0f);
	this->rad=0.0f;
}

inline void BoundBox::Calc()
{
	this->ctr=(this->min+this->max)*0.5f;
	this->rad=(this->ctr-this->min).Length();
}
